package top.goldenyear.porpoise.infra.job.service;

import cn.hutool.v7.core.text.StrUtil;
import com.easy.query.api.proxy.client.EasyEntityQuery;
import com.easy.query.solon.annotation.Db;
import java.util.List;
import lombok.extern.slf4j.Slf4j;
import org.noear.solon.annotation.Component;
import org.noear.solon.scheduling.ScheduledAnno;
import org.noear.solon.scheduling.ScheduledException;
import org.noear.solon.scheduling.scheduled.JobHandler;
import top.goldenyear.porpoise.common.core.exception.ErrorCode;
import top.goldenyear.porpoise.common.core.exception.ServiceException;
import top.goldenyear.porpoise.common.core.model.PlainOption;
import top.goldenyear.porpoise.common.core.util.solon.SolonUtils;
import top.goldenyear.porpoise.framework.web.core.model.PageResult;
import top.goldenyear.porpoise.framework.web.core.model.query.QPage;
import top.goldenyear.porpoise.framework.web.core.service.BaseService;
import top.goldenyear.porpoise.infra.job.model.Job;
import top.goldenyear.porpoise.infra.job.model.proxy.JobProxy;
import top.goldenyear.porpoise.infra.job.util.JobManagerUtils;

/**
 * 定时任务表 Service 服务层
 *
 * @author airhead
 * @since 2024-12-21
 */
@Component
@Slf4j
public class JobService extends BaseService<Job, JobProxy> {
  @Db private EasyEntityQuery easyEntityQuery;

  public JobService() {
    super(Job.class, JobProxy.class);
  }

  public Boolean createJob(Job job) {
    boolean save = save(job);
    if (save) {
      toggleJob(job, job.getStatus().equals(1));
    }

    return save;
  }

  public Boolean updateJob(Job job) {
    boolean update = updateById(job);
    if (update) {
      toggleJob(job, job.getStatus().equals(1));
    }

    return true;
  }

  public Boolean toggleJob(Long id, Boolean status) {
    Job job = validateExist(id);
    if (Boolean.TRUE.equals(status)) {
      start(job);
    } else {
      stop(job);
    }

    return true;
  }

  public Boolean toggleJob(Job job, Boolean status) {
    if (Boolean.TRUE.equals(status)) {
      start(job);
    } else {
      stop(job);
    }

    return true;
  }

  public Job getJob(Long id) {
    return getById(id);
  }

  public Boolean deleteJob(Long id) {
    validateExist(id);

    return deleteById(id);
  }

  public Boolean batchDelJob(List<Long> ids) {
    for (Long id : ids) {
      validateExist(id);
    }

    return deleteByIds(ids);
  }

  public List<Job> listJob(Job job) {
    return list(job);
  }

  public List<Job> simpleListJob(Job job) {
    return list(job);
  }

  public PageResult<Job> paginateJob(QPage qPage, Job job) {
    return paginate(qPage, job);
  }

  public List<PlainOption> optionsJob(Job job) {
    return listAs(job, PlainOption.class);
  }

  public List<Job> listAllEnable() {
    Job query = new Job();
    query.setStatus(1);

    return list(query);
  }

  public void startAll() {
    List<Job> jobs = listAllEnable();

    for (Job job : jobs) {
      start(job);
    }
  }

  public void stopAll() {
    List<Job> jobs = listAllEnable();

    for (Job job : jobs) {
      stop(job);
    }
  }

  @Override
  protected EasyEntityQuery easyEntityQuery() {
    return easyEntityQuery;
  }

  private Job validateExist(Long id) {
    Job job = getById(id);
    if (job == null) {
      throw new ServiceException(ErrorCode.builder().msg("记录不存在").build());
    }

    return job;
  }

  private void stop(Job job) {
    if (!JobManagerUtils.exists(job.getName())) {
      return;
    }

    try {
      JobManagerUtils.stop(job.getName());
    } catch (ScheduledException e) {
      log.error("stop job error, job name: {}", job.getName(), e);
    }
  }

  private void start(Job job) {
    if (JobManagerUtils.exists(job.getName())) {
      return;
    }

    JobHandler jobHandler = SolonUtils.getBean(job.getHandlerName());
    if (jobHandler == null) {
      log.error(
          "jobHandler is null, job name: {}, job handler: {}", job.getName(), job.getHandlerName());
    }

    if (StrUtil.isBlank(job.getCronExpression())) {
      log.error(
          "cron is empty, job name: {}, job handler: {}", job.getName(), job.getHandlerName());
    }

    JobManagerUtils.add(
        job.getName(), new ScheduledAnno().cron(job.getCronExpression()), jobHandler);
  }
}
